package format

import (
	"context"
	"fmt"
	"strconv"
	"time"

	gormLogger "gorm.io/gorm/logger"
)

// Logger .
type Logger struct {
	LogLevel gormLogger.LogLevel
}

// LogMode log mode
func (l *Logger) LogMode(level gormLogger.LogLevel) gormLogger.Interface {
	newLogger := *l
	newLogger.LogLevel = level
	return &newLogger
}

// Info print info
func (l Logger) Info(ctx context.Context, msg string, data ...interface{}) {
	if l.LogLevel < gormLogger.Info {
		return
	}
	logInfo := "[gorm] " + msg + fmt.Sprintf("%v", data)
	commonLogger, err := GetLogger(ctx)
	if err != nil {
		return
	}
	commonLogger.Info(logInfo)
}

// Warn print warn messages
func (l Logger) Warn(ctx context.Context, msg string, data ...interface{}) {
	if l.LogLevel < gormLogger.Warn {
		return
	}
	logInfo := "[gorm] " + msg + fmt.Sprintf("%v", data)
	commonLogger, err := GetLogger(ctx)
	if err != nil {
		return
	}
	commonLogger.Warn(logInfo)
}

// Error print error messages
func (l Logger) Error(ctx context.Context, msg string, data ...interface{}) {
	if l.LogLevel < gormLogger.Error {
		return
	}

	logInfo := "[gorm] " + msg + fmt.Sprintf("%v", data)
	commonLogger, err := GetLogger(ctx)
	if err != nil {
		return
	}
	commonLogger.Error(logInfo)

}

// Trace print sql message
func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
	if l.LogLevel <= gormLogger.Silent {
		return
	}
	elapsed := time.Since(begin)
	sql, rows := fc()
	logInfo := "[gorm] " + elapsed.String() + " " + sql + " | " + strconv.Itoa(int(rows)) + " rows returned"
	commonLogger, err := GetLogger(ctx)
	if err != nil {
		commonLogger = NewLogger(LogSilent, LogData{
			TraceID: "",
			Action:  "init",
		})
	}
	if commonLogger.traceFunc != nil {
		commonLogger.traceFunc(logInfo)
	}
	commonLogger.Trace(logInfo)
}
